home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / ncurses-5.3 / tack / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  14.6 KB  |  819 lines

  1. /*
  2. ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
  3. ** 
  4. ** This file is part of TACK.
  5. ** 
  6. ** TACK is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2, or (at your option)
  9. ** any later version.
  10. ** 
  11. ** TACK is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** 
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with TACK; see the file COPYING.  If not, write to
  18. ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. ** Boston, MA 02111-1307, USA.
  20. */
  21. /* screen formatting and I/O utility functions */
  22.  
  23. #include <tack.h>
  24. #include <time.h>
  25.  
  26. MODULE_ID("$Id: output.c,v 1.7 2001/06/18 18:44:40 tom Exp $")
  27.  
  28. /* globals */
  29. long char_sent;            /* number of characters sent */
  30. int char_count;            /* counts characters */
  31. int line_count;            /* counts line feeds */
  32. int expand_chars;        /* length of expand() string */
  33. int replace_mode;        /* used to output replace mode padding */
  34. int can_go_home;        /* TRUE if we can fashion a home command */
  35. int can_clear_screen;        /* TRUE if we can somehow clear the screen */
  36. int raw_characters_sent;    /* Total output characters */
  37. int log_count;            /* Number of characters on a log line */
  38.  
  39. /* translate mode default strings */
  40. #define TM_carriage_return    TM_string[0].value
  41. #define TM_cursor_down        TM_string[1].value
  42. #define TM_scroll_forward    TM_string[2].value
  43. #define TM_newline        TM_string[3].value
  44. #define TM_cursor_left        TM_string[4].value
  45. #define TM_bell            TM_string[5].value
  46. #define TM_form_feed        TM_string[6].value
  47. #define TM_tab            TM_string[7].value
  48.  
  49. struct default_string_list TM_string[TM_last] = {
  50.     {"cr", "\r", 0},
  51.     {"cud1", "\n", 0},
  52.     {"ind", "\n", 0},
  53.     {"nel", "\r\n", 0},
  54.     {"cub1", "\b", 0},
  55.     {"bel", "\007", 0},
  56.     {"ff", "\f", 0},
  57.     {"ht", "\t", 0}
  58. };
  59.  
  60. static const char *c0[32] = {
  61.     "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK",
  62.     "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
  63.     "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
  64.     "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
  65. };
  66.  
  67. static const char *c1[32] = {
  68.     "", "", "", "", "IND", "NEL", "SSA", "ESA",
  69.     "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
  70.     "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
  71.     "", "", "", "CSI", "ST", "OSC", "PM", "APC"
  72. };
  73.  
  74. int
  75. getnext(int mask)
  76. {                /* get the next character without scan mode
  77.                    conversion */
  78.     int ch;
  79.     unsigned char buf;
  80.  
  81.     tc_putp(req_for_input);
  82.     fflush(stdout);
  83.     if (nodelay_read)
  84.         while (1) {
  85.             ch = read(fileno(stdin), &buf, 1);
  86.             if (ch == -1)
  87.                 return EOF;
  88.             if (ch == 1)
  89.                 return buf;
  90.         }
  91.     ch = getchar();
  92.     if (ch == EOF)
  93.         return EOF;
  94.     return ch & mask;
  95. }
  96.  
  97.  
  98. int
  99. getchp(int mask)
  100. {                /* read a character with scan mode conversion */
  101.     if (scan_mode) {
  102.         tc_putp(req_for_input);
  103.         fflush(stdout);
  104.         return scan_key();
  105.     } else
  106.         return getnext(mask);
  107. }
  108.  
  109. /*
  110. **    tc_putch(c)
  111. **
  112. **    Output one character
  113. */
  114. int
  115. tc_putch(int c)
  116. {
  117.     char_sent++;
  118.     raw_characters_sent++;
  119.     putchar(c);
  120.     if ((raw_characters_sent & 31) == 31) {
  121.         fflush(stdout);
  122.     }
  123.     if (log_fp) {
  124.         /* terminal output logging */
  125.         c = UChar(c);
  126.         if (c < 32) {
  127.             fprintf(log_fp, "<%s>", c0[c]);
  128.             log_count += 5;
  129.         } else
  130.         if (c < 127) {
  131.             fprintf(log_fp, "%c", c);
  132.             log_count += 1;
  133.         } else {
  134.             fprintf(log_fp, "<%02x>", c);
  135.             log_count += 4;
  136.         }
  137.         if (c == '\n' || log_count >= 80) {
  138.             fprintf(log_fp, "\n");
  139.             log_count = 0;
  140.         }
  141.     }
  142.     return (c);
  143. }
  144.  
  145. /*
  146. **    tt_tputs(string, reps)
  147. **
  148. **    Output a string with tputs() translation.
  149. **    Use this function inside timing tests.
  150. */
  151. void
  152. tt_tputs(const char *string, int reps)
  153. {
  154.     int i;
  155.  
  156.     if (string) {
  157.         for (i = 0; i < TT_MAX; i++) {
  158.             if (i >= ttp) {
  159.                 tt_cap[i] = string;
  160.                 tt_affected[i] = reps;
  161.                 tt_count[i] = 1;
  162.                 tt_delay[i] = msec_cost(string, reps);
  163.                 ttp++;
  164.                 break;
  165.             }
  166.             if (string == tt_cap[i] && reps == tt_affected[i]) {
  167.                 tt_count[i]++;
  168.                 tt_delay_used += tt_delay[i];
  169.                 break;
  170.             }
  171.         }
  172.         (void) tputs(string, reps, tc_putch);
  173.     }
  174. }
  175.  
  176. /*
  177. **    tt_putp(string)
  178. **
  179. **    Output a string with tputs() translation.
  180. **    Use this function inside timing tests.
  181. */
  182. void
  183. tt_putp(const char *string)
  184. {
  185.     tt_tputs(string, 1);
  186. }
  187.  
  188. /*
  189. **    tt_putparm(string, reps, arg1, arg2, ...)
  190. **
  191. **    Send tt_tputs(tparm(string, args...), reps)
  192. **    Use this function inside timing tests.
  193. */
  194. void
  195. tt_putparm(
  196.     NCURSES_CONST char *string,
  197.     int reps,
  198.     int arg1,
  199.     int arg2)
  200. {
  201.     int i;
  202.  
  203.     if (string) {
  204.         for (i = 0; i < TT_MAX; i++) {
  205.             if (i >= ttp) {
  206.                 tt_cap[i] = string;
  207.                 tt_affected[i] = reps;
  208.                 tt_count[i] = 1;
  209.                 tt_delay[i] = msec_cost(string, reps);
  210.                 ttp++;
  211.                 break;
  212.             }
  213.             if (string == tt_cap[i] && reps == tt_affected[i]) {
  214.                 tt_count[i]++;
  215.                 tt_delay_used += tt_delay[i];
  216.                 break;
  217.             }
  218.         }
  219.         (void) tputs(tparm((NCURSES_CONST char *)string, arg1, arg2), reps, tc_putch);
  220.     }
  221. }
  222.  
  223. /*
  224. **    tc_putp(string)
  225. **
  226. **    Output a string with tputs() translation.
  227. **    Use this function instead of putp() so we can track
  228. **    the actual number of characters sent.
  229. */
  230. int
  231. tc_putp(const char *string)
  232. {
  233.     return tputs(string, 1, tc_putch);
  234. }
  235.  
  236.  
  237. void
  238. put_this(int c)
  239. {                /* output one character (with padding) */
  240.     tc_putch(c);
  241.     if (char_padding && replace_mode)
  242.         tt_putp(char_padding);
  243. }
  244.  
  245.  
  246. void
  247. put_cr(void)
  248. {
  249.     if (translate_mode && carriage_return) {
  250.         tt_putp(carriage_return);
  251.     } else {
  252.         tt_putp(TM_carriage_return);
  253.     }
  254.     char_count = 0;
  255. }
  256.  
  257.  
  258. void
  259. put_lf(void)
  260. {                /* send a linefeed (only works in RAW or
  261.                    CBREAK mode) */
  262.     if (translate_mode && cursor_down) {
  263.         tt_putp(cursor_down);
  264.     } else {
  265.         tt_putp(TM_cursor_down);
  266.     }
  267.     line_count++;
  268. }
  269.  
  270.  
  271. void
  272. put_ind(void)
  273. {                /* scroll forward (only works in RAW or
  274.                    CBREAK mode) */
  275.     if (translate_mode && scroll_forward) {
  276.         tt_putp(scroll_forward);
  277.     } else {
  278.         tt_putp(TM_scroll_forward);
  279.     }
  280.     line_count++;
  281. }
  282.  
  283. /*
  284. **    put_crlf()
  285. **
  286. **    Send (nel)  or <cr> <lf>
  287. */
  288. void
  289. put_crlf(void)
  290. {
  291.     if (translate_mode && newline) {
  292.         tt_putp(newline);
  293.     } else {
  294.         tt_putp(TM_newline);
  295.     }
  296.     char_count = 0;
  297.     line_count++;
  298. }
  299.  
  300. /*
  301. **    put_new_lines(count)
  302. **
  303. **    Send a number of newlines. (nel)
  304. */
  305. void
  306. put_newlines(int n)
  307. {
  308.     while (n-- > 0) {
  309.         put_crlf();
  310.     }
  311. }
  312.  
  313. /*
  314. **    putchp(character)
  315. **
  316. **    Send one character to the terminal.
  317. **    This function does translation of control characters.
  318. */
  319. void
  320. putchp(int c)
  321. {
  322.     switch (c) {
  323.     case '\b':
  324.         if (translate_mode && cursor_left) {
  325.             tt_putp(cursor_left);
  326.         } else {
  327.             tt_putp(TM_cursor_left);
  328.         }
  329.         char_count--;
  330.         break;
  331.     case 7:
  332.         if (translate_mode && bell) {
  333.             tt_putp(bell);
  334.         } else {
  335.             tt_putp(TM_bell);
  336.         }
  337.         break;
  338.     case '\f':
  339.         if (translate_mode && form_feed) {
  340.             tt_putp(form_feed);
  341.         } else {
  342.             tt_putp(TM_form_feed);
  343.         }
  344.         char_count = 0;
  345.         line_count++;
  346.         break;
  347.     case '\n':
  348.         put_crlf();
  349.         break;
  350.     case '\r':
  351.         put_cr();
  352.         break;
  353.     case '\t':
  354.         if (translate_mode && tab) {
  355.             tt_putp(tab);
  356.         } else {
  357.             tt_putp(TM_tab);
  358.         }
  359.         char_count = ((char_count / 8) + 1) * 8;
  360.         break;
  361.     default:
  362.         put_this(c);
  363.         char_count++;
  364.         break;
  365.     }
  366. }
  367.  
  368.  
  369. void
  370. put_str(const char *s)
  371. {                /* send the string to the terminal */
  372.     for (; *s; putchp(*s++));
  373. }
  374.  
  375.  
  376. void
  377. putln(const char *s)
  378. {                /* output a string followed by a CR LF */
  379.     for (; *s; putchp(*s++));
  380.     put_crlf();
  381. }
  382.  
  383.  
  384. void
  385. put_columns(const char *s, int len, int w)
  386. {                /* put out s in column format */
  387.     int l;
  388.  
  389.     if (char_count + w > columns) {
  390.         put_crlf();
  391.     }
  392.     l = char_count % w;
  393.     if (l) {
  394.         while (l < w) {
  395.             putchp(' ');
  396.             l++;
  397.         }
  398.     }
  399.     if (char_count && char_count + len >= columns) {
  400.         put_crlf();
  401.     }
  402.     l = char_count;
  403.     put_str(s);
  404.     char_count = l + len;
  405. }
  406.  
  407.  
  408. /*
  409. **    ptext(string)
  410. **
  411. **    Output a string but do not assume the terminal will wrap to a
  412. **    new line.  Break the line at a word boundary then send a CR LF.
  413. **    This is more esthetic on 40 column terminals.
  414. */
  415. void
  416. ptext(const char *s)
  417. {
  418.     const char *t;
  419.  
  420.     while (*s) {
  421.         for (t = s + 1; *t > ' '; t++);
  422.         if ((char_count != 0) && ((t - s) + char_count >= columns)) {
  423.             put_crlf();
  424.             while (*s == ' ')
  425.                 s++;
  426.         }
  427.         while (s < t) {
  428.             putchp(*s++);
  429.         }
  430.     }
  431. }
  432.  
  433.  
  434. void
  435. put_dec(char *f, int i)
  436. {                /* print a line with a decimal number in it */
  437.     char tm[128];
  438.  
  439.     sprintf(tm, f, i / 10, i % 10);
  440.     ptext(tm);
  441. }
  442.  
  443.  
  444. void
  445. three_digit(char *tx, int i)
  446. {                /* convert the decimal number to a string of
  447.                    at least 3 digits */
  448.     if (i < 1000)
  449.         sprintf(tx, "%d.%d", i / 10, i % 10);
  450.     else
  451.         sprintf(tx, "%d", i / 10);
  452. }
  453.  
  454.  
  455. void
  456. ptextln(const char *s)
  457. {                /* print the text using ptext() then add a CR
  458.                    LF */
  459.     ptext(s);
  460.     put_crlf();
  461. }
  462.  
  463.  
  464. static void
  465. expand_one(int ch, char **v)
  466. {                /* expand one character */
  467.     char *t = *v;
  468.  
  469.     if (ch & 0x80) {    /* dump it in octal (yuck) */
  470.         *t++ = '\\';
  471.         *t++ = '0' + ((ch >> 6) & 3);
  472.         *t++ = '0' + ((ch >> 3) & 7);
  473.         *t++ = '0' + (ch & 7);
  474.         expand_chars += 4;
  475.     } else if (ch == 127) {    /* DEL */
  476.         *t++ = '^';
  477.         *t++ = '?';
  478.         expand_chars += 2;
  479.     } else if (ch >= ' ') {
  480.         *t++ = ch;
  481.         expand_chars++;
  482.     } else {    /* control characters */
  483.         *t++ = '^';
  484.         *t++ = ch + '@';
  485.         expand_chars += 2;
  486.     }
  487.     *v = t;
  488. }
  489.  
  490.  
  491. char *
  492. expand(const char *s)
  493. {                /* convert the string to printable form */
  494.     static char buf[4096];
  495.     char *t, *v;
  496.     int ch;
  497.  
  498.     if (magic_cookie_glitch <= 0 && exit_attribute_mode) {
  499.         v = enter_reverse_mode;
  500.     } else {
  501.         v = NULL;
  502.     }
  503.     expand_chars = 0;
  504.     t = buf;
  505.     if (s) {
  506.         for (; (ch = *s); s++) {
  507.             if ((ch & 0x80) && v) {    /* print it in reverse video
  508.                            mode */
  509.                 strcpy(t, liberated(tparm(v)));
  510.                 for (; *t; t++);
  511.                 expand_one(ch & 0x7f, &t);
  512.                 strcpy(t, liberated(tparm(exit_attribute_mode)));
  513.                 for (; *t; t++);
  514.             } else {
  515.                 expand_one(ch, &t);
  516.             }
  517.         }
  518.     }
  519.     *t = '\0';
  520.     return buf;
  521. }
  522.  
  523.  
  524. char *
  525. print_expand(char *s)
  526. {                /* convert the string to 7-bit printable form */
  527.     static char buf[4096];
  528.     char *t;
  529.     int ch;
  530.  
  531.     expand_chars = 0;
  532.     t = buf;
  533.     if (s) {
  534.         for (; (ch = *s); s++) {
  535.             expand_one(ch, &t);
  536.         }
  537.     }
  538.     *t = '\0';
  539.     return buf;
  540. }
  541.  
  542.  
  543. char *
  544. expand_to(char *s, int l)
  545. {                /* expand s to length l */
  546.     char *t;
  547.  
  548.     for (s = t = expand(s); *t; t++);
  549.     for (; expand_chars < l; expand_chars++) {
  550.         *t++ = ' ';
  551.     }
  552.     *t = '\0';
  553.     return s;
  554. }
  555.  
  556.  
  557. char *
  558. hex_expand_to(char *s, int l)
  559. {                /* expand s to length l in hex */
  560.     static char buf[4096];
  561.     char *t;
  562.  
  563.     for (t = buf; *s; s++) {
  564.         sprintf(t, "%02X ", UChar(*s));
  565.         t += 3;
  566.         if (t - buf > (int) sizeof(buf) - 4) {
  567.             break;
  568.         }
  569.     }
  570.     for (; t - buf < l;) {
  571.         *t++ = ' ';
  572.     }
  573.     *t = '\0';
  574.     expand_chars = t - buf;
  575.     return buf;
  576. }
  577.  
  578.  
  579. char *
  580. expand_command(const char *c)
  581. {                /* expand an ANSI escape sequence */
  582.     static char buf[256];
  583.     int i, j, ch;
  584.     char *s;
  585.  
  586.     s = buf;
  587.     for (i = FALSE; (ch = UChar(*c)) != 0; c++) {
  588.         if (i) {
  589.             *s++ = ' ';
  590.         }
  591.         i = TRUE;
  592.         if (ch < 32) {
  593.             j = UChar(c[1]);
  594.             if (ch == '\033' && j >= '@' && j <= '_') {
  595.                 ch = j - '@';
  596.                 c++;
  597.                 for (j = 0; (*s = c1[ch][j++]); s++);
  598.             } else
  599.                 for (j = 0; (*s = c0[ch][j++]); s++);
  600.         } else {
  601.             *s++ = ch;
  602.             j = UChar(c[1]);
  603.             if (ch >= '0' && ch <= '9' &&
  604.                 j >= '0' && j <= '9') {
  605.                 i = FALSE;
  606.             }
  607.         }
  608.     }
  609.     *s = '\0';
  610.     return buf;
  611. }
  612.  
  613. /*
  614. **    go_home()
  615. **
  616. **    Move the cursor to the home position
  617. */
  618. void
  619. go_home(void)
  620. {
  621.     int i;
  622.  
  623.     if (cursor_home)
  624.         tt_putp(cursor_home);
  625.     else if (cursor_address)
  626.         tt_putparm(cursor_address, lines, 0, 0);
  627.     else if (row_address) {    /* use (vpa) */
  628.         put_cr();
  629.         tt_putparm(row_address, 1, 0, 0);
  630.     } else if (cursor_up && cursor_to_ll) {
  631.         tt_putp(cursor_to_ll);
  632.         for (i = 1; i < lines; i++) {
  633.             tt_putp(cursor_up);
  634.         }
  635.     } else {
  636.         can_go_home = FALSE;
  637.         return;
  638.     }
  639.     char_count = line_count = 0;
  640.     can_go_home = TRUE;
  641. }
  642.  
  643.  
  644. void
  645. home_down(void)
  646. {                /* move the cursor to the lower left hand
  647.                    corner */
  648.     int i;
  649.  
  650.     if (cursor_to_ll)
  651.         tt_putp(cursor_to_ll);
  652.     else if (cursor_address)
  653.         tt_putparm(cursor_address, lines, lines - 1, 0);
  654.     else if (row_address) {    /* use (vpa) */
  655.         put_cr();
  656.         tt_putparm(row_address, 1, lines - 1, 0);
  657.     } else if (cursor_down && cursor_home) {
  658.         tt_putp(cursor_home);
  659.         for (i = 1; i < lines; i++)
  660.             tt_putp(cursor_down);
  661.     } else
  662.         return;
  663.     char_count = 0;
  664.     line_count = lines - 1;
  665. }
  666.  
  667.  
  668. void
  669. put_clear(void)
  670. {                /* clear the screen */
  671.     int i;
  672.  
  673.     if (clear_screen)
  674.         tt_tputs(clear_screen, lines);
  675.     else if (clr_eos && can_go_home) {
  676.         go_home();
  677.         tt_tputs(clr_eos, lines);
  678.     } else if (scroll_forward && !over_strike && (can_go_home || cursor_up)) {
  679.         /* clear the screen by scrolling */
  680.         put_cr();
  681.         if (cursor_to_ll) {
  682.             tt_putp(cursor_to_ll);
  683.         } else if (cursor_address) {
  684.             tt_putparm(cursor_address, lines, lines - 1, 0);
  685.         } else if (row_address) {
  686.             tt_putparm(row_address, 1, lines - 1, 0);
  687.         } else {
  688.             for (i = 1; i < lines; i++) {
  689.                 tt_putp(scroll_forward);
  690.             }
  691.         }
  692.         for (i = 1; i < lines; i++) {
  693.             tt_putp(scroll_forward);
  694.         }
  695.         if (can_go_home) {
  696.             go_home();
  697.         } else {
  698.             for (i = 1; i < lines; i++) {
  699.                 tt_putp(cursor_up);
  700.             }
  701.         }
  702.     } else {
  703.         can_clear_screen = FALSE;
  704.         return;
  705.     }
  706.     char_count = line_count = 0;
  707.     can_clear_screen = TRUE;
  708. }
  709.  
  710. /*
  711. **    wait_here()
  712. **
  713. **    read one character from the input stream
  714. **    If the terminal is not in RAW mode then this function will
  715. **    wait for a <cr> or <lf>.
  716. */
  717. int
  718. wait_here(void)
  719. {
  720.     char ch, cc[64];
  721.     char message[16];
  722.     int i, j;
  723.  
  724.     for (i = 0; i < (int) sizeof(cc); i++) {
  725.         cc[i] = ch = getchp(STRIP_PARITY);
  726.         if (ch == '\r' || ch == '\n') {
  727.             put_crlf();
  728.             char_sent = 0;
  729.             return cc[i ? i - 1 : 0];
  730.         }
  731.         if (ch >= ' ') {
  732.             if (stty_query(TTY_CHAR_MODE)) {
  733.                 put_crlf();
  734.                 char_sent = 0;
  735.                 return ch;
  736.             }
  737.             continue;
  738.         }
  739.         if (ch == 023) {    /* Control S */
  740.             /* ignore control S, but tell me about it */
  741.             while (ch == 023 || ch == 021) {
  742.                 ch = getchp(STRIP_PARITY);
  743.                 if (i < (int) sizeof(cc))
  744.                     cc[++i] = ch;
  745.             }
  746.             put_str("\nThe terminal sent a ^S -");
  747.             for (j = 0; j <= i; j++) {
  748.                 sprintf(message, " %02X", cc[j] & 0xFF);
  749.                 put_str(message);
  750.             }
  751.             put_crlf();
  752.             i = -1;
  753.         } else if (ch != 021) {    /* Not Control Q */
  754.             /* could be abort character */
  755.             spin_flush();
  756.             if (tty_can_sync == SYNC_TESTED) {
  757.                 (void) tty_sync_error();
  758.             } else {
  759.                 put_str("\n? ");
  760.             }
  761.         }
  762.     }
  763.     return '?';
  764. }
  765.  
  766.  
  767. /*
  768. **    read_string(buffer, length)
  769. **
  770. **    Read a string of characters from the input stream.
  771. */
  772. void
  773. read_string(
  774.     char *buf,
  775.     int length)
  776. {
  777.     int ch, i;
  778.  
  779.     for (i = 0; i < length - 1; ) {
  780.         ch = getchp(STRIP_PARITY);
  781.         if (ch == '\r' || ch == '\n') {
  782.             break;
  783.         }
  784.         if (ch == '\b' || ch == 127) {
  785.             if (i) {
  786.                 putchp('\b');
  787.                 putchp(' ');
  788.                 putchp('\b');
  789.                 i--;
  790.             }
  791.         } else {
  792.             buf[i++] = ch;
  793.             putchp(ch);
  794.         }
  795.     }
  796.     buf[i] = '\0';
  797.     put_crlf();
  798.     char_sent = 0;
  799. }
  800.  
  801. /*
  802. **    maybe_wait(lines)
  803. **
  804. **    wait if near the end of the screen, then clear screen
  805. */
  806. void 
  807. maybe_wait(int n)
  808. {
  809.     if (line_count + n >= lines) {
  810.         if (char_sent != 0) {
  811.             ptext("Go? ");
  812.             (void) wait_here();
  813.         }
  814.         put_clear();
  815.     } else {
  816.         put_crlf();
  817.     }
  818. }
  819.